﻿using OfficeOpenXml.Style;
using OfficeOpenXml;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Wq.Extensions.Common
{
    public class ExcelColumns<TData> : List<ExcelColumn<TData>>
    {

        public void Add(string title, Func<TData, object> field)
        {
            this.Add(new ExcelColumn<TData>(title, field));
        }
        public void Add(string title, int width, Func<TData, object> field)
        {
            this.Add(new ExcelColumn<TData>(title, width, field));
        }
    }

    public class ExcelColumn<TData>
    {
        public string Title
        {
            get;
        }
        public double Width
        {
            get;
        }
        public Func<TData, object> FuncValue
        {
            get;
        }
        public ExcelColumn(string title, Func<TData, object> funcValue)
        {
            Title = title;
            FuncValue = funcValue;
        }
        public ExcelColumn(string title, double width, Func<TData, object> funcValue)
        {
            Title = title;
            Width = width;
            FuncValue = funcValue;
        }
    }
    /// <summary>
    /// 合并单元格
    /// </summary>
    public class ExcelMergeCell
    {
        /// <summary>
        /// 开始行下标
        /// </summary>
        public int FromRow
        {
            get; set;
        }
        /// <summary>
        /// 结束行下标
        /// </summary>
        public int ToRow
        {
            get; set;
        }
        /// <summary>
        /// 开始列下标
        /// </summary>
        public int FormCol
        {
            get; set;
        }
        /// <summary>
        /// 结束列下标
        /// </summary>
        public int ToCol
        {
            get; set;
        }
    }
    public class ExcelHelper
    {
        /// <summary>
        /// 输出 ContentType
        /// </summary>
        public const string ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

        /// <summary>
        /// Excel 文件扩展名
        /// </summary>
        public const string Extension = ".xlsx";

        public static MemoryStream BuildExcel<T>(List<T> data, ExcelColumns<T> columns, List<ExcelMergeCell> merges = null)
        {
            var ms = new MemoryStream();
            using (var package = new ExcelPackage(ms))
            {
                int maxRow = 1048575;//Excel 最大行数 1048576 第一行标题
                var totalPage = 1;
                if (data.Count > maxRow)
                {
                    if (data.Count % maxRow == 0)
                        totalPage = data.Count / maxRow;
                    else
                        totalPage = data.Count / maxRow + 1;
                }

                for (int i = 1; i <= totalPage; i++)
                {
                    var sheet = package.Workbook.Worksheets.Add($"sheet{i}");
                    sheet.Cells.Style.Font.Size = 10;
                    sheet.Cells.Style.HorizontalAlignment = ExcelHorizontalAlignment.Left;
                    sheet.Cells.Style.VerticalAlignment = ExcelVerticalAlignment.Center;

                    var rowIndex = 1;
                    var columnMap = new Dictionary<int, ExcelColumn<T>>();

                    for (var columnIndex = 1; columnIndex <= columns.Count; columnIndex++)
                    {
                        var column = columns[columnIndex - 1];

                        columnMap.Add(columnIndex, column);

                        sheet.SetValue(rowIndex, columnIndex, column.Title);
                        if (column.Width > 0)
                            sheet.Column(columnIndex).Width = column.Width;
                        var cell = sheet.Cells[rowIndex, columnIndex];
                        cell.Style.Font.Bold = true;
                        cell.Style.HorizontalAlignment = ExcelHorizontalAlignment.Center;
                    }

                    for (int j = (i - 1) * maxRow; j < data.Count() && j < i * maxRow - 1; j++)
                    {
                        rowIndex++;
                        foreach (var column in columnMap)
                            sheet.SetValue(rowIndex, column.Key, column.Value.FuncValue(data[j]));
                    }



                    if (merges != null)
                    {
                        foreach (var item in merges)
                            sheet.Cells[item.FromRow - (i - 1) * maxRow, item.FormCol, item.ToRow - (i - 1) * maxRow, item.ToCol].Merge = true;
                    }

                }

                package.Save();
            }
            ms.Position = 0;
            return ms;
        }

    }
}
